home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 016a / nansi30.zip / RAW.C < prev    next >
C/C++ Source or Header  |  1990-07-14  |  7KB  |  215 lines

  1. /*--- raw.c --------------------------------------------------------------
  2.  MS-DOS routines to set and reset raw mode, enable or disable break checking,
  3.  and check for characters on stdin.
  4.  Written by Dan Kegel (dank@moc.jpl.nasa.gov).  Enjoy.
  5.  $Log:    raw.c $
  6.  * Revision 1.3  90/07/14  09:02:03  dan_kegel
  7.  * Added raw_set_stdio(), which should make it easy to use RAW mode.
  8.  * 
  9.  * Revision 1.2  90/07/09  23:18:15  dan_kegel
  10.  * Compiles with /w3 now.
  11.  * 
  12.  * Revision 1.1  90/07/09  23:11:13  dan_kegel
  13.  * Initial revision
  14.  * 
  15.  
  16.  QUICK SUMMARY:
  17.  
  18.  For fast screen output, call
  19.     raw_set_stdio(1);
  20.  at the beginning of your program, and 
  21.     raw_set_stdio(0);
  22.  at the end, and use getchar() to grab keystrokes from the keyboard.
  23.  Your screen updates will be much faster (assuming you use stdout, and
  24.  have installed NANSI.SYS or FANSI-CONSOLE), and
  25.  getchar() will treat Backspace, Enter, ^S, ^C, ^P, and ESC as normal
  26.  keystrokes rather than as editing characters.
  27.  
  28.  DETAILS and extra goodies:
  29.  
  30.  To maximize display speed, applications should set the stdout device to 
  31.  raw mode when they start up, and clear it when they exit or start up a
  32.  subshell.
  33.  It is the device associated with a file handle that has a RAW mode, not
  34.  the file handle itself.  Thus, if stdin and stdout both refer to CON:,
  35.  raw_get(fileno(stdin)) will always equal raw_get(fileno(stdout)).
  36.  
  37.  The stdin device should not be in RAW mode during normal operation 
  38.  because this disables normal command-line editing.  For example,
  39.  COPY CON: NUL: will never exit if stdin is in RAW mode.
  40.  Because RAW mode is dangerous, applications that use it should prevent
  41.  DOS from checking for Control-C or Control-Break.  This can be done by
  42.  calling break_set(0).
  43.  
  44.  To check for an input char without waiting, call raw_kbhit().
  45.  Be sure to turn off break checking before you call, unless you want
  46.  the user to be able to break out of your program!
  47.  
  48.  To use getchar() while the console is in RAW mode, you must first disable
  49.  input buffering by executing
  50.     setbuf(stdin, NULL);
  51.  or else getchar() will simply hang.
  52.  When stdin is in RAW mode, getchar() will not check for control-C,
  53.  control-S, or control-P; it will also not echo.  
  54.  (The ideas here are all UNIX-compatible, but the following code would
  55.   need changes to compile under UNIX.   Under UNIX, the only reason to
  56.   use RAW mode is to cause getchar() to not check for ^C, ^S, etc.)
  57.  
  58.  If you tend to do lots of single-character outputting to the screen,
  59.  you may need to use output buffering before you see any speed benefits from
  60.  RAW mode.  If you use putchar() to do your outputs, you can enable output
  61.  buffering by executing
  62.      static char stdoutbuf[BUFSIZ];
  63.     setbuf(stdout, stdoutbuf);
  64.  but then you you have to fflush(stdout) each time you want to be sure your
  65.  output has made it out of the buffer onto the screen.
  66. --------------------------------------------------------------------------*/
  67. #include <dos.h>
  68. #include <stdio.h>
  69. #include "raw.h"
  70.  
  71. /* IOCTL GETBITS/SETBITS bits. */
  72. #define DEVICE        0x80
  73. #define RAW        0x20
  74.  
  75. /* IOCTL operations */
  76. #define GETBITS        0
  77. #define SETBITS        1
  78. #define GETINSTATUS    6
  79.  
  80. /* DOS function numbers. */
  81. #define BREAKCHECK    0x33
  82. #define IOCTL        0x44
  83.  
  84. /* A nice way to call the DOS IOCTL function */
  85. static int
  86. ioctl(int handle, int mode, unsigned setvalue)
  87. {
  88.     union REGS regs;
  89.  
  90.     regs.h.ah = IOCTL;
  91.     regs.h.al = (char) mode;
  92.     regs.x.bx = handle;
  93.     regs.h.dl = (char) setvalue;
  94.     regs.h.dh = 0;            /* Zero out dh */
  95.     intdos(®s, ®s);
  96.     return (regs.x.dx);
  97. }
  98.  
  99. /*--------------------------------------------------------------------------
  100.  Call this routine to determinte whether the device associated with
  101.  the given file is in RAW mode.
  102.  Returns FALSE if not in raw mode, TRUE if in raw mode.
  103.  Example: old_raw = raw_get(fileno(stdin));
  104. --------------------------------------------------------------------------*/
  105. int
  106. raw_get(fd)
  107.     int fd;
  108. {
  109.     return ( RAW == (RAW & ioctl(fd, GETBITS, 0)));
  110. }
  111.  
  112. /*--------------------------------------------------------------------------
  113.  Call this routine to set or clear RAW mode for the device associated with
  114.  the given file.
  115.  Example: raw_set(fileno(stdout), TRUE);
  116. --------------------------------------------------------------------------*/
  117. void
  118. raw_set(fd, raw)
  119.     int fd;
  120.     int raw;
  121. {
  122.     int bits;
  123.     bits = ioctl(fd, GETBITS, 0);
  124.     if (DEVICE & bits) {
  125.         if (raw)
  126.             bits |= RAW;
  127.         else
  128.             bits &= ~RAW;
  129.         (void) ioctl(fd, SETBITS, bits);
  130.     }
  131. }
  132.  
  133. /*--------------------------------------------------------------------------
  134.  If any input is ready on stdin, return a nonzero value.
  135.  Else return zero.
  136.  This works for both input files and devices.
  137.  In RAW mode, if break checking is turned off, does not check for ^C.
  138.  (The kbhit() that comes with Microsoft C seems to always check for ^C.)
  139. ----------------------------------------------------------------------------*/
  140. int
  141. raw_kbhit()
  142. {
  143.     union REGS regs;
  144.  
  145.     regs.h.ah = IOCTL;
  146.     regs.h.al = GETINSTATUS;
  147.     regs.x.bx = fileno(stdin);
  148.     intdos(®s, ®s);
  149.     return (0xff & regs.h.al);
  150. }
  151.  
  152.  
  153. /* A nice way to call the DOS BREAKCHECK function */
  154. static int
  155. breakctl(int mode, int setvalue)
  156. {
  157.     union REGS regs;
  158.  
  159.     regs.h.ah = BREAKCHECK;
  160.     regs.h.al = (char) mode;
  161.     regs.h.dl = (char) setvalue;
  162.     intdos(®s, ®s);
  163.     return (regs.x.dx & 0xff);
  164. }
  165.  
  166. /*--------------------------------------------------------------------------
  167.  Call this routine to determine whether DOS is checking for break (Control-C)
  168.  before it executes any DOS function call.
  169.  Return value is FALSE if it only checks before console I/O function calls,
  170.  TRUE if it checks before any function call.
  171. --------------------------------------------------------------------------*/
  172. int
  173. break_get(void)
  174. {
  175.     return ( 0 != breakctl(GETBITS, 0));
  176. }
  177.  
  178. /*--------------------------------------------------------------------------
  179.  Call this routine with TRUE to tell DOS to check for break (Control-C)
  180.  before it executes any DOS function call.
  181.  Call this routine with FALSE to tell DOS to only check for break before
  182.  it executes console I/O function calls.
  183. --------------------------------------------------------------------------*/
  184. void
  185. break_set(check)
  186.     int check;
  187. {
  188.     (void) breakctl(SETBITS, check);
  189. }
  190.  
  191. /*--------------------------------------------------------------------------
  192.  One routine to set (or clear) raw mode on stdin and stdout,
  193.  clear (or restore) break checking, and turn off input buffering on stdin.
  194.  This is the most common configuration; under MS-DOS, since setting raw mode
  195.  on stdout sometimes sets it on stdin, it's best to set it on both & be done
  196.  with it.
  197. --------------------------------------------------------------------------*/
  198. void
  199. raw_set_stdio(raw)
  200.     int raw;    /* TRUE -> set raw mode; FALSE -> clear raw mode */
  201. {
  202.     static int was_break_checking = 0;
  203.  
  204.     raw_set(fileno(stdin), raw);
  205.     raw_set(fileno(stdout), raw);
  206.     if (raw) {
  207.         setbuf(stdin, NULL);    /* so getchar() won't hang */
  208.         was_break_checking = break_get();
  209.         break_set(0);
  210.     } else {
  211.         break_set(was_break_checking);
  212.     }
  213. }
  214.  
  215.